package com.ncloud.resman.busi;

import com.alibaba.druid.sql.visitor.functions.If;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ncloud.common.enmus.ResultEnum;
import com.ncloud.common.exception.UserException;
import com.ncloud.monitor.inter.MonitorInterface;
import com.ncloud.resman.constant.ResConstant;
import com.ncloud.resman.entity.*;
import com.ncloud.resman.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Created by shiqiang on 2017/8/28.
 */
@Service
public class VirtualMachineBusi {
    @Autowired
    private DeviceUnitService deviceUnitService;
    @Autowired
    private VirtualMachineService virtualMachineService;
    @Autowired
    private VirtualDiskService virtualDiskService;

    @Autowired
    private VirtualNetworkCardService virtualNetworkCardService;
    @Autowired
    private MonitorInterface monitorInterface;

    @Autowired
    private IpAddressService ipAddressService;
    /*虚拟机新增*/
    @Transactional
    public void addVirtualMachine(VirtualMachine virtualMachine, JSONObject jsonObject){
        if(virtualMachine.getCreateUser() == null){
            virtualMachine.setCreateUser(jsonObject.getLong("userID"));
        }
        virtualMachine.setState(ResConstant.VIRTUAL_STATE_HANG);
        /*插入虚拟机信息*/
        virtualMachineService.insertVirtualMachine(virtualMachine);

        /*插入硬盘信息*/
        virtualMachine.getVirtualDisks().stream().forEach(virtualDisk -> {

            virtualDisk.setVirtualId(virtualMachine.getVirtualId());
            if(virtualDisk.getCreateUser()==null){
                virtualDisk.setCreateUser(jsonObject.getLong("userID"));
            }
            virtualDisk.setState("1");
            virtualDiskService.insertVirtualDisk(virtualDisk);
        });


        /*插入网卡信息*/
        virtualMachine.getVirtualNetworkCards().stream().forEach(virtualNetworkCard -> {
            /*校验ip合法性*/
            validateIpUse(virtualNetworkCard.getCardIp());
            virtualNetworkCard.setVirtualId(virtualMachine.getVirtualId());
            if(virtualNetworkCard.getCreateUser()==null){
                virtualNetworkCard.setCreateUser(jsonObject.getLong("userID"));
            }
            virtualNetworkCard.setState("1");
            virtualNetworkCardService.insertVirtualNetworkCard(virtualNetworkCard);
        });
    }


    /*更新虚拟机*/
    @Transactional
    public void updateVirtualMachine(VirtualMachine virtualMachine, JSONObject jsonObject){
        if(virtualMachine.getUpdateUser() == null){
            virtualMachine.setUpdateUser(jsonObject.getLong("userID"));
        }
        virtualMachineService.updateVirtualMachine(virtualMachine);

        /*更新虚拟机磁盘*/
        virtualMachine.getVirtualDisks().stream().forEach(virtualDisk -> {
            if(virtualDisk.getDiskId() == null){
                virtualDisk.setVirtualId(virtualMachine.getVirtualId());
                if(virtualDisk.getCreateUser()==null){
                    virtualDisk.setCreateUser(jsonObject.getLong("userID"));
                }
                virtualDisk.setState("1");
                virtualDiskService.insertVirtualDisk(virtualDisk);
            }else{
                virtualDisk.setUpdateUser(jsonObject.getLong("userID"));
                virtualDiskService.updateVirtualDisk(virtualDisk);
            }

        });
        /*更新虚拟机网卡*/
        virtualMachine.getVirtualNetworkCards().stream().forEach(virtualNetworkCard -> {

            if(virtualNetworkCard.getCardId() == null){
                virtualNetworkCard.setVirtualId(virtualMachine.getVirtualId());
                if(virtualNetworkCard.getCreateUser()==null){
                    virtualNetworkCard.setCreateUser(jsonObject.getLong("userID"));
                }
                virtualNetworkCard.setState("1");
                virtualNetworkCardService.insertVirtualNetworkCard(virtualNetworkCard);
                  /*校验ip合法性*/
                validateIpUse(virtualNetworkCard.getCardIp());
            }else{
                VirtualNetworkCard cardOld = virtualNetworkCardService.getVirtualNetworkCardById(virtualNetworkCard.getCardId());
                if(!cardOld.getCardIp().equals(virtualNetworkCard.getCardIp())){
                    IpAddress oldIp = new IpAddress();
                    oldIp.setIp(cardOld.getCardIp());
                    oldIp.setState("0");
                    ipAddressService.updateIpState(oldIp);
                     /*校验ip合法性*/
                    validateIpUse(virtualNetworkCard.getCardIp());
                }
                virtualNetworkCard.setUpdateUser(jsonObject.getLong("userID"));
                virtualNetworkCardService.updateVirtualNetworkCard(virtualNetworkCard);
            }
        });
    }

    /*查询ip状态信息*/
    private void validateIpUse(String ip){
        int flag = ipAddressService.isIpValid(ip);
        if(flag == 2){
            throw new UserException(ResultEnum.PARAM_ERROR.getCode(),ip+" 地址已经被使用，重新选择！");
        }else{
            IpAddress ipAddress = new IpAddress();
            ipAddress.setState("1");
            ipAddress.setIp(ip);
            ipAddressService.updateIpState(ipAddress);
        }
    }
    /*获取修改的虚机信息*/
    //public VirtualMachine getVirtualMachineByDeviceId()
    /*删除虚拟机*/
    @Transactional
    public void deleteVirtualMachine(Long virtualId){
        VirtualMachine virtualMachine = virtualMachineService.getVirtualMachineById(virtualId);
        if(virtualMachine == null || !ResConstant.VIRTUAL_STATE_STOP.equals(virtualMachine.getState())){
            throw new UserException(ResultEnum.PARAM_ERROR.getCode(),"只有停止的虚拟机，才可以删除！");
        }
        virtualMachineService.deleteVirtualMachine(virtualId);
        virtualDiskService.deleteVirtualDiskByVirtualId(virtualId);
        virtualNetworkCardService.deleteVirtualCardByVirtualId(virtualId);
        virtualNetworkCardService.getVirtualNetworkVirtualId(virtualId).stream().forEach(virtualNetworkCard -> {
            IpAddress oldIp = new IpAddress();
            oldIp.setIp(virtualNetworkCard.getCardIp());
            oldIp.setState("0");
            ipAddressService.updateIpState(oldIp);
        });
    }
    /*获取菜单树结构数据*/
    public JSONObject getRoomTreeInfo(){
        JSONObject json = new JSONObject();
        /*获取机房信息*/
        List<JSONObject> rooms = virtualMachineService.getRoomAll().stream().map(room->{
            /*机柜信息*/
            List<JSONObject> cabinets= virtualMachineService.getCabinetByRoomId(room.getLong("roomId")).stream().map(cabinet->{
                /*服务器信息*/
                 List<JSONObject> servers = virtualMachineService.getDeviceServerByCabinetId(cabinet.getLong("cabinetId")).stream().map(server->{
                     /*虚拟机*/
                     server.put("virtualMachines",virtualMachineService.getVirtualMachineByDeviceId(server.getLong("deviceId")));
                     return server;
                 }).collect(Collectors.toList());
                cabinet.put("servers",servers);
                return cabinet;
            }).collect(Collectors.toList());
            room.put("cabinets",cabinets);
            return room;
        }).collect(Collectors.toList());
        json.put("rooms",rooms);
        return json;
    }
                /*6	CPU
            7	内存
            8	硬盘
            9	电源
            10	网卡
            11	控制卡*/
    public long computeSurplusSpace(Long deviceId,String type){
        long totalSum = 0;
        long used =0;
        switch (type){
            case ResConstant.UNIT_TYPE_CPU:
                totalSum = getUnitTypeTotal(deviceId,type);
                used = virtualMachineService.getVirtualMachineByDeviceId(deviceId).stream().map(v->v.getCpuNum()).
                        reduce(0,(cpuNum,element)-> cpuNum + element);
                break;
            case ResConstant.UNIT_TYPE_DISK:
                break;
            case ResConstant.UNIT_TYPE_RAM:
                totalSum = getUnitTypeTotal(deviceId,type);
                used = virtualMachineService.getVirtualMachineByDeviceId(deviceId).stream().map(v->Integer.parseInt(v.getMemoryCapacity())).
                        reduce(0,(cpuNum,element)-> cpuNum + element);
                break;
            case ResConstant.UNIT_TYPE_POWER:
                break;
            case ResConstant.UNIT_TYPE_ADAPTER:
                break;
        }
        return totalSum - used;
    }


    private long getUnitTypeTotal(Long deviceId,String type){
        List<DeviceUnit> list = deviceUnitService.getDeviceUnitByType(deviceId,type);
        return list.stream().filter(deviceUnit -> deviceUnit.getCapacity()!=null ).map(deviceUnit ->{
            int total = 0;
            if(deviceUnit.getAmount()==null){
                deviceUnit.setAmount(1);
            }
            try {
                int amount = deviceUnit.getAmount();
                int capacity = Integer.parseInt(deviceUnit.getCapacity());
                total = amount * capacity;
            }catch (Exception e){
                e.printStackTrace();
            }
            return total;
        }).reduce(0,(cpuNum,element)-> cpuNum + element);
    }

    /*根据ip计算服务器硬盘信息,可用磁盘容量*/
    public long getDiskCapacity(String hostIp){
        long totalSum = 0;
        long used =0;
        List<DeviceUnit> list = deviceUnitService.getDeviceUnitByIpmi(hostIp,ResConstant.UNIT_TYPE_DISK);
        totalSum = list.stream().filter(deviceUnit -> deviceUnit.getCapacity()!=null ).map(deviceUnit ->{
            long totalTemp = 0;
            if(deviceUnit.getAmount()==null){
                deviceUnit.setAmount(1);
            }
            try {
                int amount = deviceUnit.getAmount();
                int capacity = Integer.parseInt(deviceUnit.getCapacity());
                totalTemp = amount * capacity;
            }catch (Exception e){
                e.printStackTrace();
            }
            return totalTemp;
        }).reduce(0L,(num,element)-> num + element);;
        used = virtualDiskService.getVirtualDiskByHostIp(hostIp).stream().map(disk->Integer.parseInt(disk.getDiskCapacity())).
                reduce(0,(num,element)-> num + element);
        return totalSum - used;
    }

    /*获取服务器主机信息*/
    public JSONObject getServerInfo(Long deviceId){
        JSONObject jsonObject = new JSONObject();
        JSONObject base = virtualMachineService.getDeviceServerBaseInfo(deviceId);
        jsonObject.put("server_base",base);
        /*资源分配信息*/
        JSONObject serverResource = new JSONObject();
        JSONObject cpu = new JSONObject();
        JSONObject memory = new JSONObject();
        JSONObject disk = new JSONObject();
        List<JSONObject> virtualCpuList = new ArrayList<JSONObject>();
        List<JSONObject> virtualMemoryList = new ArrayList<JSONObject>();
        List<JSONObject> virtualDiskList = new ArrayList<JSONObject>();
        long cpuTotal = getUnitTypeTotal(deviceId,ResConstant.UNIT_TYPE_CPU);
        cpu.put("total",cpuTotal);
        long memoryTotal = getUnitTypeTotal(deviceId,ResConstant.UNIT_TYPE_RAM);
        memory.put("total",memoryTotal);
        long diskTotal = getUnitTypeTotal(deviceId,ResConstant.UNIT_TYPE_DISK);
        disk.put("total",diskTotal);
        List<VirtualMachine> virtualMachines = virtualMachineService.getVirtualMachineByDeviceId(deviceId);
        cpu.put("unUsed",cpuTotal - virtualMachines.stream().map(v->v.getCpuNum()).reduce(0,(cpuNum,element)-> cpuNum + element));
        memory.put("unUsed",memoryTotal - virtualMachines.stream().map(v->Integer.parseInt(v.getMemoryCapacity())).reduce(0,(cpuNum,element)-> cpuNum + element));
        virtualMachines.stream().forEach(virtualMachine -> {
            virtualStateDeal(virtualMachine);
            /*虚拟机cpu处理*/
            JSONObject virtualCpu = new JSONObject();
            virtualCpu.put("name",virtualMachine.getVirtualHostName());
            virtualCpu.put("value",virtualMachine.getCpuNum());
            virtualCpuList.add(virtualCpu);
             /*虚拟机内存处理*/
            JSONObject virtualMemory = new JSONObject();
            virtualMemory.put("name",virtualMachine.getVirtualHostName());
            virtualMemory.put("value",virtualMachine.getMemoryCapacity());
            virtualMemoryList.add(virtualMemory);
            /*计算硬盘使用情况*/
            List<VirtualDisk> virtualDisks = virtualDiskService.getVirtualDiskByVirtualId(virtualMachine.getVirtualId());
            /*挂载载当前主机下的虚拟硬盘信息*/
            List<VirtualDisk> virtualDisksServer = virtualDisks.stream().filter(
                    mydisk -> mydisk.getHostIp().equals(base.getString("ipmiAddr"))).collect(Collectors.toList());
            JSONObject virtualDisk = new JSONObject();
            virtualDisk.put("name",virtualMachine.getVirtualHostName());
            virtualDisk.put("value",virtualDisksServer.stream().map(d->Integer.parseInt(d.getDiskCapacity())).
                    reduce(0,(num,element)-> num + element));
            virtualDiskList.add(virtualDisk);
            //设置列表信息
            virtualMachine.setVirtualDisks(virtualDisks);
            virtualMachine.setVirtualNetworkCards(virtualNetworkCardService.getVirtualNetworkVirtualId(virtualMachine.getVirtualId()));
        });
        disk.put("unUsed",diskTotal - virtualDiskList.stream().map(obj->obj.getIntValue("value")).
                reduce(0,(num,element)-> num + element));
        jsonObject.put("virtualMachines",virtualMachines);
        /*设置资源信息*/
        cpu.put("virtualCpu",virtualCpuList);
        serverResource.put("cpu",cpu);
        disk.put("virtualDisk",virtualDiskList);
        serverResource.put("disk",disk);
        memory.put("virtualMemory",virtualMemoryList);
        serverResource.put("memory",memory);
        jsonObject.put("server_resource",serverResource);
        return jsonObject;
    }

    private void virtualStateDeal(VirtualMachine virtualMachine){
        switch (virtualMachine.getState()){
            case ResConstant.VIRTUAL_STATE_RUNNING:
                virtualMachine.setStateName("运行");
                break;
            case ResConstant.VIRTUAL_STATE_SUSPEND:
                virtualMachine.setStateName("暂停");
                break;
            case ResConstant.VIRTUAL_STATE_HANG:
                virtualMachine.setStateName("挂起");
                break;
            case ResConstant.VIRTUAL_STATE_STOP:
                virtualMachine.setStateName("停止");
                break;
        }
    }

    public JSONObject getVirtualMachineInfo(Long virtualId){
        JSONObject jsonObject = new JSONObject();
        /*定义虚拟机基本信息*/
        JSONObject virtualBase = new JSONObject();
        VirtualMachine virtualMachine = virtualMachineService.getVirtualMachineById(virtualId);
        if(virtualMachine !=null){
            virtualStateDeal(virtualMachine);
            List<VirtualNetworkCard> virtualNetworkCards = virtualNetworkCardService.getVirtualManageIp(virtualId);
            if(virtualNetworkCards.size() != 1){
                throw new UserException(ResultEnum.PARAM_ERROR.getCode(),"管理网ip地址有且只有一条！");
            }
            virtualBase = JSON.parseObject(JSON.toJSONString(virtualMachine));
            virtualBase.put("manageIp",virtualNetworkCards.get(0).getCardIp());
            jsonObject.put("virtualMachineBase",virtualBase);
            /*虚拟主机资源使用率信息*/
            try {
               List<Map<String,Object>> resourceList = monitorInterface.getUsedRatioByHostManageIp("zabbix",virtualNetworkCards.get(0).getCardIp());
                jsonObject.put("virtualResource",resourceList);
            }catch (Exception e){
                e.printStackTrace();
                jsonObject.put("virtualResource",new JSONArray());
            }
            /*虚拟机配置详情信息*/
            virtualMachine.setVirtualNetworkCards(virtualNetworkCardService.getVirtualNetworkVirtualId(virtualId));
            virtualMachine.setVirtualDisks(virtualDiskService.getVirtualDiskByVirtualId(virtualId));

            jsonObject.put("virtualMachineDetail",virtualMachine);
        }else {
            throw new UserException(ResultEnum.PARAM_ERROR.getCode(),"没有对应的虚机信息！"+virtualId);
        }
        return jsonObject;
    }
}
